import asyncio
from typing import Optional

from connection_manager import ConnectionManager
from log import error, info
from protocol_codec import encode, decode
from config import CMD_PING
from router.message_router import MessageRouter
from router.ping_handler import ping_handler


class TcpServer:
    """
    模块化 TCP 异步服务端（抽象接口）
    - 管理客户端连接
    - 提供发送/广播方法
    - 消息路由通过外部注册
    """

    def __init__(self, host: str = '0.0.0.0', port: int = 8765):
        self.host = host
        self.port = port
        # self.server 可以是 asyncio.AbstractServer 类型，也可以是 None
        self.server: Optional[asyncio.AbstractServer] = None
        self.manager = ConnectionManager()
        self.router = MessageRouter()
        self.router.register(CMD_PING, ping_handler)

    async def start(self):
        """启动 TCP 服务端"""
        self.server = await asyncio.start_server(self.handle_client, self.host, self.port)
        info(f"[Server] 启动成功，监听 {self.host}:{self.port}")

        async with self.server:
            await self.server.serve_forever()

    async def handle_client(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
        """处理新连接"""
        addr = writer.get_extra_info('peername')
        self.manager.add_connection(addr, writer)
        info(f"[Server] 新连接：{addr}")

        try:
            while True:
                data = await reader.read(1024)
                if not data:
                    break

                message = decode(data)
                info(f"[Server] 收到来自 {addr} 的数据: {message}")

                # 调用 MessageRouter 处理消息（具体 handler 由使用者注册）
                response = await self.router.route(message, addr)
                if response:
                    writer.write(encode(response))
                    await writer.drain()

        except Exception as e:
            error(f"[Server] 连接异常 {addr}: {e}")
        finally:
            info(f"[Server] 断开连接: {addr}")
            self.manager.remove_connection(addr)
            writer.close()
            await writer.wait_closed()

    async def send_to(self, addr, message: str):
        """主动向指定客户端发送消息"""
        writer = self.manager.get_connection(addr)
        if writer:
            writer.write(encode(message))
            await writer.drain()
        else:
            error(f"[Server] 找不到连接 {addr}")

    async def broadcast(self, message: str):
        """向所有客户端广播消息"""
        for addr, writer in self.manager.connections.items():
            try:
                writer.write(encode(message))
                await writer.drain()
            except Exception as e:
                error(f"[Server] 向 {addr} 发送失败: {e}")

